/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package de.swta.freezay.database.controller;

import de.swta.freezay.database.controller.exceptions.NonexistentEntityException;
import de.swta.freezay.database.controller.exceptions.PreexistingEntityException;
import de.swta.freezay.database.dbEntities.Unit;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import de.swta.freezay.database.dbEntities.Item;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Christian
 */
public class UnitJpaController {

    public UnitJpaController() {
        emf = Persistence.createEntityManagerFactory("FreezayPU");
    }
    private EntityManagerFactory emf = null;

    public List<Unit> findUnitEntities(int maxResults, int firstResult,
            String sortBy, boolean ascending) {

        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Unit as o order "
                    + "by o." + sortBy + " " + (ascending ? "ASC" : "DESC"));

            q.setMaxResults(maxResults);
            q.setFirstResult(firstResult);

            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Unit unit) throws PreexistingEntityException, Exception {
        if (unit.getItemCollection() == null) {
            unit.setItemCollection(new ArrayList<Item>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            List<Item> attachedItemCollection = new ArrayList<Item>();
            for (Item itemCollectionItemToAttach : unit.getItemCollection()) {
                itemCollectionItemToAttach = em.getReference(itemCollectionItemToAttach.getClass(), itemCollectionItemToAttach.getId());
                attachedItemCollection.add(itemCollectionItemToAttach);
            }
            unit.setItemCollection(attachedItemCollection);
            em.persist(unit);
            for (Item itemCollectionItem : unit.getItemCollection()) {
                Unit oldUnitOfItemCollectionItem = itemCollectionItem.getUnit();
                itemCollectionItem.setUnit(unit);
                itemCollectionItem = em.merge(itemCollectionItem);
                if (oldUnitOfItemCollectionItem != null) {
                    oldUnitOfItemCollectionItem.getItemCollection().remove(itemCollectionItem);
                    oldUnitOfItemCollectionItem = em.merge(oldUnitOfItemCollectionItem);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findUnit(unit.getId()) != null) {
                throw new PreexistingEntityException("Unit " + unit + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Unit unit) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Unit persistentUnit = em.find(Unit.class, unit.getId());
            List<Item> itemCollectionOld = persistentUnit.getItemCollection();
            List<Item> itemCollectionNew = unit.getItemCollection();
            List<Item> attachedItemCollectionNew = new ArrayList<Item>();
            for (Item itemCollectionNewItemToAttach : itemCollectionNew) {
                itemCollectionNewItemToAttach = em.getReference(itemCollectionNewItemToAttach.getClass(), itemCollectionNewItemToAttach.getId());
                attachedItemCollectionNew.add(itemCollectionNewItemToAttach);
            }
            itemCollectionNew = attachedItemCollectionNew;
            unit.setItemCollection(itemCollectionNew);
            unit = em.merge(unit);
            for (Item itemCollectionOldItem : itemCollectionOld) {
                if (!itemCollectionNew.contains(itemCollectionOldItem)) {
                    itemCollectionOldItem.setUnit(null);
                    itemCollectionOldItem = em.merge(itemCollectionOldItem);
                }
            }
            for (Item itemCollectionNewItem : itemCollectionNew) {
                if (!itemCollectionOld.contains(itemCollectionNewItem)) {
                    Unit oldUnitOfItemCollectionNewItem = itemCollectionNewItem.getUnit();
                    itemCollectionNewItem.setUnit(unit);
                    itemCollectionNewItem = em.merge(itemCollectionNewItem);
                    if (oldUnitOfItemCollectionNewItem != null && !oldUnitOfItemCollectionNewItem.equals(unit)) {
                        oldUnitOfItemCollectionNewItem.getItemCollection().remove(itemCollectionNewItem);
                        oldUnitOfItemCollectionNewItem = em.merge(oldUnitOfItemCollectionNewItem);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = unit.getId();
                if (findUnit(id) == null) {
                    throw new NonexistentEntityException("The unit with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Unit unit;
            try {
                unit = em.getReference(Unit.class, id);
                unit.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The unit with id " + id + " no longer exists.", enfe);
            }
            List<Item> itemCollection = unit.getItemCollection();
            for (Item itemCollectionItem : itemCollection) {
                itemCollectionItem.setUnit(null);
                itemCollectionItem = em.merge(itemCollectionItem);
            }
            em.remove(unit);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }


    public boolean isUsed(Integer id) {
        boolean inUse = false;

        Unit unitToTest = this.findUnit(id);

        if (unitToTest != null) {
            inUse = unitToTest.getItemCollection().size() != 0;
        }
        return inUse;
    }


    public List<Unit> findUnitEntities() {
        return findUnitEntities(true, -1, -1);
    }

    public List<String> getUnitNames() {
        List<Unit> units = this.findUnitEntities();
        List<String> unitNames = new ArrayList<String>();

        for (int i = 0; i < units.size(); i++) {
            unitNames.add(units.get(i).getName());
        }

        return unitNames;
    }

    public List<Unit> findUnitEntities(int maxResults, int firstResult) {
        return findUnitEntities(false, maxResults, firstResult);
    }

    private List<Unit> findUnitEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Unit as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Unit findUnit(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Unit.class, id);
        } finally {
            em.close();
        }
    }

    public int getUnitCount() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Unit as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
